/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileNameExtensionFilter;
import model.Camera;
import model.Configuracoes;
import model.Heightmap;
import model.IluminacaoConstante;
import model.MalhaTriangularIrregular;
import model.ManipuladorArquivo;
import model.Oculta;
import model.Suavizacao;
import model.estrutura.Esfera;
import model.estrutura.MalhaIrregular;
import model.estrutura.MalhaRegular;

/**
 *
 * @author Thiago
 */
public final class Activity extends JFrame implements ActionListener {
    
    private MalhaIrregular malhaTriangularIrregular;
    private MalhaRegular malhaTriangularRegular;
    private Esfera esfera;
    private MalhaTriangularIrregular geradorMalhaIrregular;
    private JFileChooser fileChooser;
    private Configuracoes config = Configuracoes.getInstance();
    private Picasso picasso;
    private Thread thread;
    private Camera cam = Camera.getInstance();
    private ManipuladorArquivo ManipuladorArquivo;
    private Heightmap heig;
    private TelaHeightmap telaHeig;
    private boolean irregularVisivel;
    IluminacaoConstante ilu = null;
    Oculta oculta = null;
    
    private final double velocidade = 5.0;
    //Objetos do menu
    JMenuBar menuBar;
    JMenu arquivo;
    JMenu malha;
    JMenu visualizacao;
    JMenu configuracoes;
    JMenu iluminacao;
    JMenuItem parametrosIluminacao;
    JMenuItem ativarIluminacao;
    JMenuItem arquivo_novo;
    JMenuItem arquivo_abrir;
    JMenuItem arquivo_salvar;
    JMenuItem arquivo_sair;
    JMenuItem malha_gerar;
    JMenuItem heightmap_gerar;
    JMenuItem suavizar_malha;
    JMenuItem ocultacaoFace;
    JRadioButtonMenuItem visualizacao_isometrica;
    JRadioButtonMenuItem visualizacao_perspectiva;
    JMenuItem configuracoes_geral;
    Draw tela;
    
//    MalhaTriangularIrregular malha;
    double[][] matrizMalha;

    public Activity() throws IOException {
        //this.esfera = new Esfera();
        this.setLayout(new BorderLayout());
        this.setTitle("CgMalhaCar3D");
        this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setSize(500, 500);
        this.irregularVisivel = true;
        //Adiciona um evento para quando a Activity estiver fechando...
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent evt) {
                encerraThread();
            }
        });

        //Adiciona os KeyListeners...
        this.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent e) {
                // Mover câmera e ponto focal para a esquerda
                if (e.getKeyCode() == KeyEvent.VK_A) {
                    cam.incVx(-velocidade);
                    cam.incPx(-velocidade);
                }

                //mover a câmera e o ponto focal para a direita
                if (e.getKeyCode() == KeyEvent.VK_S) {
                    cam.incVx(velocidade);
                    cam.incPx(velocidade);
                }

                //mover a câmera e o ponto focal para baixo 
                if (e.getKeyCode() == KeyEvent.VK_Q) {
                    cam.incVy(-velocidade);
                    cam.incPy(-velocidade);
                }

                //mover a câmera e o ponto focal para cima
                if (e.getKeyCode() == KeyEvent.VK_W) {
                    cam.incVy(velocidade);
                    cam.incPy(velocidade);
                }

                //Aproximar a câmera do ponto focal
                if (e.getKeyCode() == KeyEvent.VK_Z) {
                    //cam.incVz(-velocidade); //Verificar...............................
                    double vx = 0;
                    double vy = 0;
                    double vz = 0;
                    
                    vx = ((cam.getVx() - cam.getPx()) * 0.05)*-1;
                    vy = ((cam.getVy() - cam.getPy()) * 0.05)*-1;
                    vz = ((cam.getVz() - cam.getPz()) * 0.05)*-1;
                    
                    cam.incVx(vx);
                    cam.incVy(vy);
                    cam.incVz(vz);
                    
                }

                //Afastar a câmera do ponto focal
                if (e.getKeyCode() == KeyEvent.VK_X) {
                    //cam.incVz(velocidade); //Verificar...............................
                    
                    double vx = 0;
                    double vy = 0;
                    double vz = 0;
                    
                    vx = ((cam.getVx() - cam.getPx()) * 0.05);
                    vy = ((cam.getVy() - cam.getPy()) * 0.05);
                    vz = ((cam.getVz() - cam.getPz()) * 0.05);
                    
                    cam.incVx(vx);
                    cam.incVy(vy);
                    cam.incVz(vz);
                }

                //Fazer o movimento de Roll para a esquerda 
                if (e.getKeyCode() == KeyEvent.VK_E) {
                    //cam.incVx(-velocidade); //Verificar...............................
                    double radiano = 0;                    
                    cam.setAng(cam.getAng() + 5);
                    radiano = (cam.getAng() * 3.14159265359 /180);
                    cam.setYx(Math.sin(radiano));
                    cam.setYy(Math.cos(radiano));
                }

                //Fazer o movimento de Roll para a direita 
                if (e.getKeyCode() == KeyEvent.VK_R) {
                    //cam.incVx(velocidade); //Verificar...............................
                    double radiano = 0;
                    cam.setAng(cam.getAng() - 5);
                    radiano = (cam.getAng() * 3.14159265359 /180);
                    cam.setYx(Math.sin(radiano));
                    cam.setYy(Math.cos(radiano));
                }

                //Fazer o movimento de Azimuth para a esquerda 
                if (e.getKeyCode() == KeyEvent.VK_D) {
                    cam.incPx(velocidade);
                }

                //Fazer o movimento de Azimuth para a direita
                if (e.getKeyCode() == KeyEvent.VK_F) {
                    cam.incPx(-velocidade);
                }

                //Fazer o movimento de Elevation para cima 
                if (e.getKeyCode() == KeyEvent.VK_C) {
                    cam.incPy(-velocidade);
                }

                //Fazer o movimento de Elevation para baixo
                if (e.getKeyCode() == KeyEvent.VK_V) {
                    cam.incPy(velocidade);
                }

                //Mover o ponto focal para a esquerda                
                if (e.getKeyCode() == KeyEvent.VK_T) {
                    cam.incPx(-velocidade);
                }

                //Mover o ponto focal para a direita
                if (e.getKeyCode() == KeyEvent.VK_Y) {
                    cam.incPx(velocidade);
                }

                //Mover o ponto focal para cima
                if (e.getKeyCode() == KeyEvent.VK_G) {
                    cam.incPy(-velocidade);
                }

                //Mover o ponto focal para baixo
                if (e.getKeyCode() == KeyEvent.VK_H) {
                    cam.incPy(velocidade);
                }

                //Aproximar o ponto focal da câmera
                if (e.getKeyCode() == KeyEvent.VK_B) {
                    cam.incPz(-velocidade);
                }

                //Afastar o ponto focal da câmera
                if (e.getKeyCode() == KeyEvent.VK_N) {
                    cam.incPz(velocidade);
                }

                //Aproximar o plano de projeção da posição da câmera
                if (e.getKeyCode() == KeyEvent.VK_MINUS) {
                    cam.incDp((int) velocidade);
                }

                //Afastar o plano de projeção da posição da câmera 
                if (e.getKeyCode() == KeyEvent.VK_EQUALS) {
                    if (cam.getDp() > 10) {
                        cam.incDp(-((int) velocidade));
                    }
                }
                printa();
            }

            @Override
            public void keyTyped(KeyEvent e) {

            }

            @Override
            public void keyReleased(KeyEvent e) {

            }
        });

        initComponents();

        this.setVisible(true);

        this.picasso = new Picasso();
        this.tela.setPicasso(picasso);
        picasso.setTela(tela);
        this.thread = new Thread(picasso);
        this.thread.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == arquivo_novo) {
            this.esfera = new Esfera();
            this.esfera.generateSphere(200, 10, 10);
            this.matrizMalha = this.esfera.getMatriz();
            posVRP();
        }
        
        if (e.getSource() == arquivo_sair) {
            this.dispose();
        }

        if (e.getSource() == configuracoes_geral) {
            try {
                new telaConfiguracao(this);
            } catch (IOException ex) {
                Logger.getLogger(Activity.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (e.getSource() == arquivo_abrir) {
            geradorMalhaIrregular = new MalhaTriangularIrregular();

            //Configurações do componente
            this.fileChooser = new JFileChooser();
            this.fileChooser.setDialogTitle("Selecione uma malha");
            String[] EXTENSION=new String[]{"cgmc","cgmh"};
            this.fileChooser.setFileFilter(new FileNameExtensionFilter("Malha files", EXTENSION));
            this.fileChooser.setAcceptAllFileFilterUsed(false);
            this.fileChooser.setMultiSelectionEnabled(false);
            if (this.fileChooser.showOpenDialog(this) == this.fileChooser.APPROVE_OPTION) {
                try {
                    
                    String filename = this.fileChooser.getSelectedFile().getName();
                    filename = filename.substring(this.fileChooser.getSelectedFile().getName().lastIndexOf("."),filename.length());
                    
                    if(filename.equals(".cgmh")){
                        this.ManipuladorArquivo = new ManipuladorArquivo(this.heig);
                    
                        this.ManipuladorArquivo.openHeightMap(this.fileChooser.getSelectedFile().getAbsolutePath());
                    
                        this.heig = this.ManipuladorArquivo.getHeig();
                        
                        System.out.println(this.heig.getTamanho());
                    }
                    if(filename.equals(".cgmc")){
                        this.ManipuladorArquivo = new ManipuladorArquivo(this.malhaTriangularIrregular, this.cam);
                    
                        this.ManipuladorArquivo.openFile(this.fileChooser.getSelectedFile().getAbsolutePath());
                    
                        this.malhaTriangularIrregular = this.ManipuladorArquivo.getMalhaIrregular();
                        this.cam = this.ManipuladorArquivo.getCamera();
                    
                        this.matrizMalha = this.malhaTriangularIrregular.getMatriz();
                        
                        System.out.println(this.malhaTriangularIrregular.toString());
                        printa();
                    }
                } catch (Exception ex) {
                    Logger.getLogger(Activity.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        if (e.getSource() == arquivo_salvar) {
            this.fileChooser = new JFileChooser();
            this.fileChooser.setDialogTitle("Salvar malha como");
            this.fileChooser.setFileFilter(new FileNameExtensionFilter("cgmc", "cgmc"));
            this.fileChooser.setAcceptAllFileFilterUsed(false);
            this.fileChooser.setMultiSelectionEnabled(false);
            if (this.fileChooser.showSaveDialog(this) == this.fileChooser.APPROVE_OPTION) {
                try {
                    this.ManipuladorArquivo = new ManipuladorArquivo(this.malhaTriangularIrregular, this.cam);
                    this.ManipuladorArquivo.saveFile(this.fileChooser.getSelectedFile() + ".cgmc");
//                    System.out.println(this.malhaTriangularIrregular.toString());
                } catch (Exception ex) {
                    Logger.getLogger(Activity.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        if (e.getSource() == malha_gerar) {
            //Carrega as configurações da malha
            try {
                config.openConfiguracoes();
            } catch (IOException ex) {
                Logger.getLogger(Activity.class.getName()).log(Level.SEVERE, null, ex);
            }
            //Gera a malha trinagular irregular com as configurações
            geradorMalhaIrregular = new MalhaTriangularIrregular();
            geradorMalhaIrregular.gerarMalha(config.getNumeroPontos(), config.getDimensaoTerreno(), config.getAlturaTerreno());
            //Converte da estrutura da malha para a estrutura do programa
            //this.esfera = new Esfera();
            //this.esfera.generateSphere(1000, 10, 10);
//            this.esfera.setVisible();
            this.malhaTriangularIrregular = new MalhaIrregular();
            this.malhaTriangularIrregular.setMalha(geradorMalhaIrregular.getIterator());
            //Converte da estrutura para a matriz
            matrizMalha = this.malhaTriangularIrregular.getMatriz();
            // para desativar iluminacao
            tela.setEstrutura(null);
            ilu = null;
            posVRP();
        }

        if (e.getSource() == suavizar_malha) {
            if (malhaTriangularIrregular != null) {
                new Suavizacao(malhaTriangularIrregular);
                matrizMalha = malhaTriangularIrregular.getMatriz();
                printa();
            }
        }

        if (e.getSource() == visualizacao_isometrica) {
            visualizacao_perspectiva.setSelected(false);
           // this.vrpIso();
            printa();
            //REPINTARRRR NA VISAO
        }
        if (e.getSource() == visualizacao_perspectiva) {
            visualizacao_isometrica.setSelected(false);
            //this.vrpPers();
            printa();
            //REPINTARRRR NA VISAO
        }
        
        if(e.getSource() == heightmap_gerar){
            //Carrega as configurações da malha
            try {
                config.openConfiguracoes();
            } catch (IOException ex) {
                Logger.getLogger(Activity.class.getName()).log(Level.SEVERE, null, ex);
            }
            this.heig = new Heightmap(config.getDimensaoTerreno());
            this.heig.gerarHeightmap();
            this.telaHeig = new TelaHeightmap(this.heig, this.malhaTriangularRegular, this);
        }
        
        if(e.getSource() == ativarIluminacao){
            this.ilu = new IluminacaoConstante(malhaTriangularIrregular, cam);
            malhaTriangularIrregular.newListaCor(malhaTriangularIrregular.getMatriz()[0].length);
            ilu.executaConstante();
            this.malhaTriangularIrregular = ilu.getMalha();
            tela.setEstrutura(malhaTriangularIrregular);
            printa();
        }
        
        if(e.getSource() == parametrosIluminacao){
            ParametrosLuminosidade l = new ParametrosLuminosidade(cam, this);
        }
        
        if(e.getSource() == ocultacaoFace){
            malhaTriangularIrregular.setOcultacao(true);
            Oculta oculta = new Oculta(malhaTriangularIrregular, cam);
            malhaTriangularIrregular.newListaCor(malhaTriangularIrregular.getMatriz()[0].length);
            oculta.executaConstante();
            malhaTriangularIrregular = oculta.getMalha();
            tela.setEstrutura(malhaTriangularIrregular);
            printa();
        }
    }
    
    public void aplicaIluminacao(){
        this.ilu = new IluminacaoConstante(malhaTriangularIrregular, cam);
        ilu.executaConstante();
        this.malhaTriangularIrregular = ilu.getMalha();
        tela.setEstrutura(malhaTriangularIrregular);
    }
    
    public void aplicaOcultacao(){
        this.oculta = new Oculta(malhaTriangularIrregular, cam);
        oculta.executaConstante();
        this.malhaTriangularIrregular = oculta.getMalha();
        tela.setEstrutura(malhaTriangularIrregular);
    }

    public void posVRP() {
        double maxX = 0, maxY = 0;
        double minX = 99999, minY = 99999;

        for (int j = 0; j < matrizMalha[0].length; j++) {
            if (maxX < matrizMalha[0][j]) {
                maxX = matrizMalha[0][j];
            }
            if (maxY < matrizMalha[1][j]) {
                maxY = matrizMalha[1][j];
            }
            if (minX > matrizMalha[0][j]) {
                minX = matrizMalha[0][j];
            }
            if (minY > matrizMalha[1][j]) {
                minY = matrizMalha[1][j];
            }
        }

        cam.setPx((maxX + minX) / 2);
        cam.setPy((maxY + minY) / 2 - 100);
        cam.setPz(0);

        cam.setVx((maxX + minX) / 2);
        cam.setVy(300);
        cam.setVz(300);
        
        cam.setLargura(maxX - minX);
        cam.setAltura(maxY - minY);

        cam.setPxISO(cam.getPx());
        cam.setPyISO(cam.getPy());
        cam.setPzISO(cam.getPz());
        
        System.out.println(cam.getVx());
        System.out.println(cam.getVy());
        System.out.println(cam.getVz());
        
        printa();
    }
    
    public void printa() {
        tela.setTipoVisao("Perspectiva");
        model.Perspectiva pers = new model.Perspectiva(this.cam, tela.getWidth(), tela.getHeight(), matrizMalha);
        tela.setMalha(pers.getPontosTela());
//        if(irregularVisivel){
//            matrizMalha = this.malhaTriangularIrregular.getMatriz();
//        }else{
//            matrizMalha = this.malhaTriangularRegular.getMatriz();
//        }
//        
//        if (geradorMalhaIrregular != null) {
//            if(ilu != null){
//                aplicaIluminacao();
//            }
//            if(oculta != null){
//                aplicaOcultacao();
//            }
//            if (visualizacao_isometrica.isSelected()) {
//                tela.setTipoVisao("Isométrica");
//                model.Isometrica iso = new model.Isometrica(this.cam, tela.getWidth(), tela.getHeight(), matrizMalha);
//                tela.setMalha(iso.getPontosTela());
//            } else {
//                if (visualizacao_perspectiva.isSelected()) {
//                    tela.setTipoVisao("Perspectiva");
//                    model.Perspectiva pers = new model.Perspectiva(this.cam, tela.getWidth(), tela.getHeight(), matrizMalha);
//                    tela.setMalha(pers.getPontosTela());
//                }
//            }
//        }
    }

    public void initComponents() {
        tela = new Draw();
        //tela.setPontos(this.esfera.generateSphere(100, 500, 500));
        tela.setBackground(new Color(255, 255, 255));

        menuBar = new JMenuBar();

        arquivo = new JMenu("Arquivo");
        arquivo_novo = new JMenuItem("Novo");
        arquivo_abrir = new JMenuItem("Abrir");
        arquivo_salvar = new JMenuItem("Salvar");
        arquivo_sair = new JMenuItem("Sair");

        malha = new JMenu("Malha");
        malha_gerar = new JMenuItem("Gerar malha irregular");
        heightmap_gerar = new JMenuItem("Gerar heightmap");
        suavizar_malha = new JMenuItem("Suavizar");
        ocultacaoFace = new JMenuItem("Ocultação de face");

        visualizacao = new JMenu("Visualização");
        visualizacao_isometrica = new JRadioButtonMenuItem("Isométrica");
        visualizacao_perspectiva = new JRadioButtonMenuItem("Perspectiva");
        
        iluminacao = new JMenu("Iluminação");
        parametrosIluminacao = new JMenuItem("Parametros Iluminação");
        ativarIluminacao = new JMenuItem("Iluminação Constante");

        configuracoes = new JMenu("Configurações");
        configuracoes_geral = new JMenuItem("Geral");

        arquivo_novo.addActionListener(this);
        arquivo_abrir.addActionListener(this);
        arquivo_salvar.addActionListener(this);
        arquivo_sair.addActionListener(this);
        malha_gerar.addActionListener(this);
        heightmap_gerar.addActionListener(this);
        suavizar_malha.addActionListener(this);
        visualizacao_isometrica.addActionListener(this);
        visualizacao_perspectiva.addActionListener(this);
        configuracoes_geral.addActionListener(this);
        parametrosIluminacao.addActionListener(this);
        ativarIluminacao.addActionListener(this);
        ocultacaoFace.addActionListener(this);

        arquivo.add(arquivo_novo);
        arquivo.add(arquivo_abrir);
        arquivo.add(arquivo_salvar);
        arquivo.add(arquivo_sair);

        malha.add(malha_gerar);
        malha.add(suavizar_malha);
        malha.add(heightmap_gerar);
        malha.add(ocultacaoFace);
        
        iluminacao.add(parametrosIluminacao);
        iluminacao.add(ativarIluminacao);

        visualizacao.add(visualizacao_perspectiva);
        visualizacao_perspectiva.setSelected(true);
        visualizacao.add(visualizacao_isometrica);

        configuracoes.add(configuracoes_geral);

        menuBar.add(arquivo);
        menuBar.add(malha);
        menuBar.add(iluminacao);
        menuBar.add(visualizacao);
        menuBar.add(configuracoes);

        this.setJMenuBar(menuBar);
        this.add(tela, BorderLayout.CENTER);
    }

    public void encerraThread() {
        if (this.thread.isAlive()) {
            this.thread.interrupt();
        }
    }

    public void setVisao(boolean b){
        this.irregularVisivel = b;
    }
    
    
    public void setCam(Camera cam){
        this.cam = cam;
    }
}
